﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using PersonaLibrary.Data;

namespace PersonaLibrary.ViewModel.PrintViewModel
{
	internal class OrderViewModel : BaseViewModel<View.PrintView.OrderView>
	{
		private ObservableCollection<OrderItem> _orderItems;
		private ObservableCollection<Employee> _employees;

		private string _filter = "Order base (*.json)|*.json|All files (*.*)|*.*";

		private RelayCommand _saveCommand;
		private RelayCommand _openCommand;
		private RelayCommand _subbmitCommand;

		public event Action Submitted;
		
		public RelayCommand SubmitCommand
		{
			get
			{
				if(_subbmitCommand == null)
					_subbmitCommand = new RelayCommand(x => Submit(), x => true);
				return _subbmitCommand;
			}
		}

		public OrderViewModel(IEnumerable<Employee> employees)
		{
			_employees = new ObservableCollection<Employee>(employees);
		}

		public RelayCommand SaveCommand
		{
			get
			{
				if(_saveCommand == null)
					_saveCommand = new RelayCommand(x => Save(), x => true);

				return _saveCommand;
			}
		}

		public RelayCommand OpenCommand
		{
			get
			{
				if (_openCommand == null)
					_openCommand = new RelayCommand(x => Open(), x => true);

				return _openCommand;
			}
		}

		private void Submit()
		{
			View.Close();
			Submitted();
		}

		public ObservableCollection<Employee> Employees
		{
			get{ return _employees; }
		}

		public ObservableCollection<OrderItem> OrderItems
		{
			get { return _orderItems; }
			set
			{
				_orderItems = value;
				RisePropertyChanged("OrderItems");
			}
		}

		protected override void OnViewCreated()
		{
			base.OnViewCreated();
			OrderItems = new ObservableCollection<OrderItem>();

			OrderItem item = new OrderItem
			                 	{
			                 		Enable = true,
			                 		OrderItems = Metadata.Instance["Employee"].Where(x => x.IsOrder).ToList()
			                 	};
			item.PropertyChanged += ItemPropertyChanged;
			OrderItems.Add(item);
			
			OrderItems.Add(CreateOrderItem());
		}

		void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			if(e.PropertyName == "Enable")
			{
				OrderItem orderSender = sender as OrderItem;
				if(orderSender != null)
				{
					if(orderSender.Enable)
						OrderItems.Add(CreateOrderItem());
					else
					{
						int index = OrderItems.IndexOf(orderSender) + 1;

						while (OrderItems.Count != index)
						{
							OrderItems[OrderItems.Count -1].PropertyChanged -= ItemPropertyChanged;
							OrderItems.RemoveAt(OrderItems.Count - 1);
						}
					}
				}
			}

			if(e.PropertyName == "SelectedIndex")
				Order();
		}

		private OrderItem CreateOrderItem()
		{
			OrderItem item = new OrderItem
			{
				Enable = false,
				OrderItems = Metadata.Instance["Employee"].Where(x => x.IsOrder).ToList()
			};
			item.PropertyChanged += ItemPropertyChanged;

			return item;
		}

		private void Order()
		{
			IOrderedQueryable<Employee> result = null;

			foreach (OrderItem orderItem in OrderItems)
			{
				if(orderItem.Enable)
				{
					var param = System.Linq.Expressions.Expression.Parameter(typeof(Employee), "person");
					var mySortExpression =
						System.Linq.Expressions.Expression.Lambda<Func<Employee, object>>(
							System.Linq.Expressions.Expression.Property(param, orderItem.SelectedItem.Name), param);

					if (orderItem.SelectedItem.RuName != "Приоритет организации")
					{
						if (result == null)
							result = Employees.AsQueryable().OrderBy(mySortExpression);
						else
							result = result.ThenBy(mySortExpression);
					}
					else
					{
						if (result == null)
							result = Employees.AsQueryable().OrderByDescending(mySortExpression);
						else
							result = result.ThenByDescending(mySortExpression);
					}
				}
			}

			if (result != null)
			{
				_employees = new ObservableCollection<Employee>(result);
				RisePropertyChanged("Employees");
			}
		}
		
		private void Save()
		{
			SaveFileDialog saveFileDialog = new SaveFileDialog
			                                	{
			                                		Filter = _filter,
			                                		CreatePrompt = true,
			                                		OverwritePrompt = true
			                                	};

			DialogResult dialogResult = saveFileDialog.ShowDialog();

			if (dialogResult == DialogResult.OK)
			{
				var ids = Employees.Select(x => x.Id);
				SaveItem itemToSave = new SaveItem{Ids = ids.ToList(), OrderItems = OrderItems};
				ServiceStack.Text.JsonSerializer.SerializeToStream(itemToSave, saveFileDialog.OpenFile());
			}
		}

		private void Open()
		{
			OpenFileDialog openFileDialog = new OpenFileDialog
			                                	{
			                                		Filter = _filter,
			                                	};

			DialogResult dialogResult = openFileDialog.ShowDialog();

			if(dialogResult == DialogResult.OK)
			{
				SaveItem item = ServiceStack.Text.JsonSerializer.DeserializeFromStream<SaveItem>(openFileDialog.OpenFile());
				for (int i = 0; i <item.Ids.Count; i++)
				{
					Employee finded = _employees.FirstOrDefault(x => x.Id == item.Ids[i]);
					if(finded != null)
					{
						int originalIndex = _employees.IndexOf(finded);
						_employees.Move(originalIndex, i);
					}
				}

				OrderItems = item.OrderItems;
				RisePropertyChanged("OrderItems");
			}
		}

		public class OrderItem : INotifyPropertyChanged
		{
			private bool _enable;
			private List<Metadata.Point> _orderItems;
			private int _selectedIndex;

			public bool Enable
			{
				get { return _enable; }
				set
				{
					_enable = value;
					RisePropertyChanged("Enable");
				}
			}

			public List<Metadata.Point> OrderItems
			{
				get { return _orderItems; }
				set
				{
					_orderItems = value;
					RisePropertyChanged("OrderItems");
				}
			}

			public int SelectedIndex
			{
				get { return _selectedIndex; }
				set
				{
					_selectedIndex = value;
					RisePropertyChanged("SelectedIndex");
				}
			}

			public Metadata.Point SelectedItem
			{
				get { return OrderItems[SelectedIndex]; }
			}

			public event PropertyChangedEventHandler PropertyChanged;

			private void RisePropertyChanged(string name)
			{
				if(PropertyChanged != null)
					PropertyChanged(this, new PropertyChangedEventArgs(name));
			}
		}

		public class SaveItem
		{
			public List<int> Ids { set; get; }

			public ObservableCollection<OrderItem> OrderItems { set; get; }
		}
	}
}
